/* 
Copyright (c) 2004,2005, 2006, 2007, 2008 University of Illinois 

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//This used to list only map elements - now it handles UL's/OL's with links
//The filename can change at some later date
AccessibilityExtension.ns(function() { with (AccessibilityExtension.LIB) {

	var AE = AccessibilityExtension.ns;  
	AE.dialogName = "accessext-form-list-navLists";
	var activeListNode = null;

	function navListItemDisplayDetails() {}
	navListItemDisplayDetails.prototype = {
		dataElementNames : ['order','linkText','linkHREF'],
		columnHeaders : ['column.header.order.label','column.header.linkText.label','column.header.href.label'],
		
		accessIssuesDataElementNames : [],
		accessIssuesMessages : [],
	}
	var navListItemDisplayDetails = new navListItemDisplayDetails();
	
	function navListItem(node,order) {
		this.order = order;
		this.parse(node);
	}
	navListItem.prototype = {
		node : null,
		order : false,
		linkText : "",
		linkHREF : "",
		alt : "",
		valid : false,
		display: true,
		displayDetails: navListItemDisplayDetails,
		parse : function(node) {
			this.node = node;
			this.valid = false;
			this.linkText = GetValueFromAttributes(this.node,['title','alt'],false);
			if (this.linkText == false) {
				this.linkText = getDisplayableTextRecursively(this.node);
				if (this.linkText == '') {
					this.linkText = accessext_getBundleSingleString('none');
				}
			}
			this.alt = GetValueFromAttributes(this.node,['alt'],accessext_getBundleSingleString('none'));
			this.linkHREF = false;
			var a = this.node.getElementsByTagName('a');
			if (a.length == 1) {
				if (a[0].hasAttribute('href')) {
					this.linkHREF = GetValueFromAttributes(a[0],['href'],"");
					this.valid = true;
				}
			} else if (this.node.tagName.toLowerCase() == 'area') {
				this.valid = true;
				this.linkHREF = GetValueFromAttributes(this.node,['href'],"");
			}
		},
		getTreeItem : function(windoc) {
			return accesxt_generateTreeboxResults(windoc,this);
		}
	}
	
	function navListDisplayDetails() {}
	navListDisplayDetails.prototype = {
		dataElementNames : ['icita07', 'icita08','displayOrder','baseuri','role','title'],
		columnHeaders : ['column.header.icita07.label', 'column.header.icita08.label','column.header.order.label','column.header.baseuri.label','column.header.role.label','column.header.NavBarTitle.label'],
		
		accessIssuesDataElementNames : ['menuwithoutheader', 'menuwithoutheaderARIA', 'nonefound'],
		accessIssuesMessages : ['navigation.warnings.menuwithoutheader', 'navigation.warnings.menuwithoutheaderARIA', 'navigation.msg.nonefound'],
	}
	var navListDisplayDetails = new navListDisplayDetails();
	
	function navList(node,order) {
		this.node = node;
		this.order = order;
		this.parseNode();
	}
	navList.prototype = {
	//	origid : "",
		id : "",
		node : null,
		icita07 : "",
		icita08 : "",
		relatednode: null,
		order : false, //0
		baseuri : "",
		role : "",
		title : "",
		alt : "",
		items : null,
		menuwithoutheader : false,
		menuwithoutheaderARIA : false,
		nonefound : false,
		nonefoundARIA : false,
		valid : false,
		display: true,
		displayDetails: navListDisplayDetails,
		parseNode : function() {
			this.baseuri = getBaseURI(this.node);
			var origid = GetValueFromAttributes(this.node,['id'],"");
			this.role = "BP";
			this.valid = false;
	
			this.title = findTitleHeaderBeforeNode(this); //also may set this.id & this.title
			if (this.id == false){this.id = origid;}
//			alert(this.order + ' Foltz parseNode:' + this.title);
			if (this.title == false) { 
				this.menuwithoutheader = true;
				this.title = findARIATitleHeaderBeforeNode(this, 2); //also may set this.id & this.title
				if (this.title == false) {
					this.title = GetValueFromAttributes(this.node,['title'],false); //SF 9/5/07 ARIA table of contents
					this.menuwithoutheaderARIA = true;
				}
			}
			
			if (this.title == false) {
				this.title = accessext_getBundleSingleString('noTitle');
			}
			
			this.alt = GetValueFromAttributes(this.node,['alt'],accessext_getBundleSingleString('none'));
			
			//Parse links
			var sub = 'li';
			if (this.node.tagName.toLowerCase() == 'dl') {
				sub = 'dt';
			} else if (this.node.tagName.toLowerCase() == 'map') {
				sub = 'area';
			} else if (this.node.tagName.toLowerCase() == 'table') {
				sub = 'td';
			}
			
			this.items = new Array();
			var nodes = this.node.getElementsByTagName(sub);
			for (var i = 0; i < nodes.length; i++) {
				var n = this.items.length;
				var item = new navListItem(nodes[i],n + 1);
				if (item.valid) {
					this.items[n] = item;
				}
			}
			
			this.valid = true;
		},
		displayOrder : 0,
		getTreeItem : function(windoc) {
			this.displayOrder = this.order; // - 1;
			return item = accesxt_generateTreeboxResults(document,this);
		},
		listDetailsInHTMLFormat : function() {
			return accesxt_generateHTMLTable('Navigation Bar ' + (this.order+1) + ' Link Elements', this.items);
		},
	}
	
AccessibilityExtension.LIB.extend(AccessibilityExtension.LIB,
{
	newNavList: function(tnode, torder) { 
		var n = new navList(torder, tnode);
		return n; 
	},
	
	isNavNode: function(node) {
		var add = true;//nl and map are already considered to be navigational
		if (node.tagName) {
			switch (node.tagName.toLowerCase()) {
				case 'table':
					add = isNavTable(node);
					break;
				case 'map':
					add = isNavMap(node);
					break;
				case 'ul':
				case 'ol':
					add = isNavList(node);
					break;
				default:
					return false;
			}
		} else {
			return false;
		}
		return add;
	}, 
	
	parseNavList: function(node, loadArray, onlyaddifhasheader) {
		var add = isNavNode(node);//nl and map are already considered to be navigational
		if (add) {
			var obj = new navList(node,loadArray.length + 1);
			if (obj.valid) {
				if (onlyaddifhasheader) {
					if (obj.title != '' && obj.title != accessext_getBundleSingleString('noTitle')) { //set in constructor's call to parseNode
						var j;
						for (j=0; j < loadArray.length && loadArray[j].title != obj.title; j++);
						if (j == loadArray.length) {
							loadArray[loadArray.length] = obj;
						}
					}
				} else {
					loadArray[loadArray.length] = obj;
				}		
			}
			return obj.valid;
		}
		return false;
	},
	
	ParseDocument: function(doc) {
		ParseDocumentMenusAndNavigation(doc, AE.primaryarray);
	},
	
	ParseDocumentMenusAndNavigation: function(docElement, loadArray) {
		try {
			//find last H1	
			var hasHTMLNav=false;
			var xp;
			var xpathResult;
			if (accessext_docUsesNamespace(docElement)) {
				xp = "//html:h1[last()]";
			} else {
				xp = "//h1[last()]";
			}
			xpathResult = docElement.evaluate(xp, docElement, accessext_NSResolver, XPathResult.ANY_TYPE,null);
			var current = xpathResult.iterateNext();
			var last = current;
			while (current) { //  //h1[last()] does not always return just the last h1
				last = current;
				current = xpathResult.iterateNext();
			}
			if (last) {
				if (accessext_docUsesNamespace(docElement)) { // find the ol,ul,map,table preceding the last h1
					xp = "preceding::*" // //html:map|preceding::*//html:ul|preceding::*//html:ol|preceding::*//html:table";
				} else {
	//the following doesn't pick all of the preceding elements needed 
	//				xp = "preceding::*//map|preceding::*//ul|preceding::*//ol|preceding::*//table";
					xp = "preceding::*";
				}
				xpathResult = docElement.evaluate(xp, last, accessext_NSResolver, XPathResult.ANY_TYPE,null);
			}
		//killed for FAE08
		//		if (accessext_docUsesNamespace(docElement)) {
		//			xp = "//html:map|//html:ul|//html:ol|//html:table";
		//		} else {
		//			xp = "//map|//ul|//ol|//table";
		//		}
		//		xpathResult = docElement.evaluate(xp, docElement, accessext_NSResolver, XPathResult.ANY_TYPE,null);
		//
			var r = xpathResult.iterateNext();
			while (r) {
				parseNavList(r, loadArray, false); //always add as nav reguardless of if it has a header 
				r = xpathResult.iterateNext();
			}
		//added for FAE08
			if (accessext_docUsesNamespace(docElement)) {
				xp = "//html:map|//html:ul|//html:ol|//html:table";
			} else {
				xp = "//map|//ul|//ol|//table";
			}
			xpathResult = docElement.evaluate(xp, docElement, accessext_NSResolver, XPathResult.ANY_TYPE,null);
			var r = xpathResult.iterateNext();
			var numNavBeforeLastH1 = loadArray.length;
			for (var navCounter = 0; r; navCounter++) {
				//http://www.dhs.state.il.us/page.aspx?item=32765 breadcrumbx 2x
				// ordinal position may  not work
				//since it is after the last h1, only add it if  it is one we have not added yet & if it has a header 
				//if (navCounter >= numNavBeforeLastH1) {
					parseNavList(r, loadArray, true); 
				//}
				r = xpathResult.iterateNext();
			}		
			if (loadArray.length > 0) {hasHTMLNav = true;}
			
			//SF 9/5/07 ARIA table of contents
			var relAttr = null;
			if (accessext_docUsesNamespace(docElement)) {
				xp = "//html:link";
			} else {
				xp = "//link";
			}
			xpathResult = docElement.evaluate(xp, docElement, accessext_NSResolver, XPathResult.ANY_TYPE,null);
			r = xpathResult.iterateNext();
			while (r) {
				if (r.hasAttribute("rel")) {
					relAttr = GetValueFromAttributes(r,['rel'],"").toLowerCase();
					if (relAttr.indexOf("navigation") >= 0) {
						var existingNodeFound = false;
						var hrefAttr = GetValueFromAttributes(r,['href'],"");
						if (hrefAttr != "") {
							hrefAttr = hrefAttr.substring(1); //remove the # from the inpage link
							for (var i = loadArray.length - 1; i >= 0; i--) {
								if (loadArray[i].id == hrefAttr) {
									loadArray[i].role = relAttr;
									loadArray[i].menuwithoutheaderARIA = loadArray[i].menuwithoutheader = false; //NA
									if (loadArray[i].title.indexOf(accessext_getBundleSingleString('noTitle')) != -1) {
										loadArray[i].title = cleanSpaces(GetValueFromAttributes(r,['title'],""));
									}
									existingNodeFound = true;
								} 
							}
						} 								
						if (existingNodeFound == false) {				
							var obj = new navList(r,loadArray.length + 1);
							obj.title = cleanSpaces(GetValueFromAttributes(r,['title'],""));
							obj.role = relAttr;
							obj.alt = "";
							obj.menuwithoutheaderARIA =obj.menuwithoutheader = false; //NA
							if (obj.valid) {
								loadArray[loadArray.length] = obj;
							}
						}
					}
				}
				r = xpathResult.iterateNext();
			} 
			
			xp = "//*[@x:role|@x2:role|@role]"; // "//*[@role]";
			xpathResult = docElement.evaluate(xp, docElement, accessext_NSResolver, XPathResult.ANY_TYPE,null);
			r = xpathResult.iterateNext();
			while (r) {
				if (r.hasAttribute("role")) {
					var roleAttr = GetValueFromAttributes(r,['role'],"").toLowerCase();
					if (roleAttr.indexOf("navigation") >= 0 || roleAttr.toLowerCase() == "menubar") {
						var existingNodeFound = false;
						var labelledby = GetValueFromAttributes(r,['aria-labelledby'],"");
						if (labelledby == "") { labelledby = GetValueFromAttributes(r,['labelledby'],""); }
						if (labelledby != "") {
							for (var i = loadArray.length - 1; i >= 0; i--) {
								if (loadArray[i].id == labelledby) {
									loadArray[i].role = roleAttr;
									loadArray[i].menuwithoutheaderARIA = false; //NA
									existingNodeFound = true;
								} 
							}
						} 				
						var title = cleanSpaces(GetValueFromAttributes(r,['title'],""));
						if (title != "" ) {
							for (var i = loadArray.length - 1; i >= 0; i--) {
								if (loadArray[i].title == title) {
									loadArray[i].role = roleAttr;
									loadArray[i].menuwithoutheaderARIA = false; //NA
									existingNodeFound = true;
								} 
							}
						}
						if (existingNodeFound == false) {
							var obj = new navList(r,loadArray.length + 1);
							obj.title = "";
							obj.menuwithoutheaderARIA = false; //NA
							obj.alt = "";
							obj.role = roleAttr;
							if (labelledby != "") {
								obj.title = accessext_getBundleSingleString('undefinedLabelledby');
							} else {
								obj.title = title;
							}
							if (obj.title == "") { obj.title = accessext_getBundleSingleString('noLabelledbyOrTitle');}					
							if (obj.valid) {
								loadArray[loadArray.length] = obj;
							}
						}				
					}
				}
				r = xpathResult.iterateNext();
			}	
			if (loadArray.length == 0 || !hasHTMLNav) {
				xp = "//html:body|//html:head|//body|//head"; //find anything on the page for the 'node'
				var xpathResult = docElement.evaluate(xp, docElement, accessext_NSResolver, XPathResult.ANY_TYPE,null);
				var r = xpathResult.iterateNext();
				var obj = new navList(r,loadArray.length + 1);
				if (obj.valid) {
					obj.title = accessext_getBundleSingleString('none');
					obj.nonefound = true;
					obj.menuwithoutheaderARIA = false;
					obj.menuwithoutheader = false;
					loadArray[loadArray.length] = obj;
					if (loadArray.length == 1 ) { // the one we just added
						loadArray[loadArray.length-1].nonefoundARIA = true;
					}
				}
			}
			setMaxSeverityForArray(loadArray);
		} catch (ex) {
			accessext_consoleDump('ParseDocumentMenusAndNavigation exception: ', ex);
		}
	},
	
	accessext_handle_treebox_main: function() {
		if (AE.treebox_main.currentIndex < 0 || AE.treebox_main.currentIndex >= AE.primaryarray.length) {
			return;
		}
			
		var findex = AE.treebox_main.currentIndex;
		var node = AE.primaryarray[findex].node;
		//SMF 9/20/07 used by accessext_PositionHighlightNode() when the navigation is off screen but the header is visible, highlight the header
		node.relatednode = AE.primaryarray[findex].relatednode;
	
		activeListNode = node;
		
		if (node == null || AE.mydoc == null) {
			if (node == null) {
				alert("Node is null");
			}
			return;
		}
		accessext_scrollToNodeCentered(node); 
		accessext_highlightNode(node); 
	
		var gotoButton = document.getElementById('button-goToURL');
		if (AE.primaryarray[findex].role.toLowerCase() != "menubar") {
			gotoButton.disabled = true;
		} else {
			gotoButton.disabled = false;
		}	
			
		accessext_setNoteText(findex);
		
		UpdateTreeView();
	},
	
	accessext_handle_treebox: function() {
		var treeChildren = AE.treebox.getElementsByTagName("treechildren");
		
		var node;
		var index = AE.treebox.currentIndex;
		if(index < 0 || index >= AE.dataarray.length || index == null){
			return;
		} else {
			//This snippet is needed for the list of links, since value!=index if duplicates removed
			var value = treeChildren[0].childNodes[index].getAttribute("value");
			node = AE.dataarray[value].node;
			index = value;
		}
		var gotoButton = document.getElementById('button-goToURL');
		if (gotoButton) {
			gotoButton.disabled = false;
		}
		
		accessext_scrollToNodeCentered(node,activeListNode);
		accessext_treeboxScrollAndHighlightNode();
	},
	
	UpdateTreeViewMain: function() {
		var sc = document.getElementById(AE.sortColumn_main);
		if (sc == null) {
			accessext_consoleDump("Could not find column: " + AE.sortColumn);
			return;
		}
	//Clear the children and create a new one
		var treeChildren = accessext_clearTreeItems(AE.treebox_main);
		accessext_clearTreeItems(AE.treebox);
		
		//Sort
		//First clear all directions
		var cols = AE.treebox_main.getElementsByTagName("treecols");
		var i;
		if (cols.length == 1) {
			for (i = 0; i < cols[0].childNodes.length; i ++) {
				cols[0].childNodes[i].setAttribute("sortDirection","");
			}
		}
	
		sc.setAttribute("sortDirection", AE.sortDirectionAscending_main ? "ascending" : "descending");
		switch (AE.sortColumn_main) {
			case "list-header-main-order":
				AE.sortProperty="order";
			break;
			case "list-header-main-text":
				AE.sortProperty="title";
			break;
			default:
				AE.sortProperty="order";
			break;
		}
		
		AE.primaryarray.sort(accessext_sortColumnElements);
		
		//Finally add elements to the list
		for (i = 0; i < AE.primaryarray.length; i ++) {
			var item = AE.primaryarray[i].getTreeItem(document);
			item.setAttribute("value", i);
			treeChildren.appendChild(item);
		}
	},
	
	UpdateTreeView: function() {
		var sc = document.getElementById(AE.sortColumn);
		if (sc == null) {
			accessext_consoleDump("Could not find column: " + AE.sortColumn);
			return;
		}
	//Clear the children and create a new one
		var treeChildren = accessext_clearTreeItems(AE.treebox);
	
		//Modifications for dual-tree view
		var findex = AE.treebox_main.currentIndex;
		if (findex < 0 || findex >= AE.primaryarray.length || findex == null) {
			AE.dataarray = new Array();
		} else {
			AE.dataarray = AE.primaryarray[findex].items;
		}	
		//Sort
		//First clear all directions
		var cols = AE.treebox.getElementsByTagName("treecols");
		var i;
		if (cols.length == 1) {
			for (i = 0; i < cols[0].childNodes.length; i ++)
				cols[0].childNodes[i].setAttribute("sortDirection","");
		}
	
		sc.setAttribute("sortDirection", AE.sortDirectionAscending ? "ascending" : "descending");
		switch (AE.sortColumn) {
			case "list-header-order":
				AE.sortProperty="order";
			break;
			case "list-header-text":
				AE.sortProperty="linkText";
			break;
			case "list-header-link":
				AE.sortProperty="linkHREF";
			break;
			default:
				AE.sortProperty="order";
			break;
		}
		
		AE.dataarray.sort(accessext_sortColumnElements);
		
		//Finally add elements to the list
		for (i = 0; i < AE.dataarray.length; i ++) {
			var item = AE.dataarray[i].getTreeItem(document);
			item.setAttribute("value", i);
			treeChildren.appendChild(item);
		}
	},
	
	GoToSelectedURL: function() {
		var findex = AE.treebox_main.currentIndex;
		if (findex  >= 0 && AE.primaryarray[findex].role.toLowerCase() == "menubar") {
			var node = AE.primaryarray[findex].node;
			if (node == null) {
				alert('node is null');
				return false;
			}
			accessext_keyboardFocusNode(node,AE.thewindow);
			return true;
	
		} else {
			var theindex = accessext_getActiveValue(AE.treebox);
			CleanUp();
			if (theindex < 0) {
				return false;
			}
			var loc = accessext_makeURLAbsolute(AE.dataarray[theindex].node.ownerDocument.location.href,AE.dataarray[theindex].linkHREF);
			
			AE.mydoc.location.href=loc;
			return true;
		}
	},
	
	mapSearchOnKeyPress: function(e) {
		var letter = String.fromCharCode(e.charCode).toLowerCase();
		var index = listboxMap.selectedIndex;
		var i;
		if (letter < 'a' || letter > 'z' || e.altKey || e.metaKey || e.ctrlKey) {
			return;
		}
	
		for (i = index + 1; i<AE.primaryarray.length; i ++) {
			if (AE.primaryarray[i].text.charAt(0).toLowerCase() == letter) {
				listboxMap.selectedIndex = i;
				listboxMap.scrollToIndex(i);
				return;
			}
		}
		for (i = 0; i < index; i ++) {
			if (AE.primaryarray[i].text.charAt(0).toLowerCase() == letter) {
				listboxMap.selectedIndex = i;
				listboxMap.scrollToIndex(i);
				return;
			}
		}
	},
	
	post_InitAccessibilityExt: function() {
		accessext_setNoteText(0);
	}
});
	if (AccessibilityExtension.LIB.InitAccessibilityExt) AccessibilityExtension.LIB.InitAccessibilityExt();	
}});